/*
Persevere - JSPON client and Persistent JavaScript implementation and strands coroutine support
Copyright (C) 2007 Xucia Incorporation
Author - Kris Zyp - kriszyp@xucia.com
  ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  * ***** END LICENSE BLOCK ***** */
function _evaler(str,scriptName) { // this is so the eval is in an outer scope
	var t;
	eval("t=" + str);
	return t;
}

(function(){
	var arrayProto = Array.prototype;
	var standardPush = arrayProto.push;
	var push = function(obj,value) {
		return standardPush.call(obj,value); // preserve default push behavoir
	};
	var isIE = !(!document.all); 
	var changeNotificationList={};
	pjs = {		
		defaultJsponPrefix:'',
		changeNotificationList:changeNotificationList,
		loaded : function(id) {
			if (dataLoaded[id]) return dataLoaded[id];
			return function (obj) {
				return obj;			
		}
	}

	};
	var dataLoaded = {};	
	var evaler = _evaler;
	var debugMode =document.location.search.indexOf("debug=true") > -1;
	delete _evaler; // make it local to this scope, but we don't want it to closure to this scope
	Suspend = {Suspended:true,toString:function() { return "SUSPENDED" }}// returned value when a coroutine is suspended, and state of the top frame when suspended
	/**
	 * This is wrap the given function in a try catch when debug mode is off. If an error is thrown, the error message will be displayed with an alert
	 */		
	var tryCatch = function(func,frame) {
		return strands.errorWrapper(func)(frame);
	}
	var specificNotify = {};
	var currentThread = {};
	var suspendedFrame;
	Future = function(func,args,thisObj,callback) {
		this.topFrames = [];
		var _this = this;
		this.fulfill = function(retValue) {
			if (retValue == specificNotify) {
				var targetFrames = retValue.targetFrames;
				retValue = retValue.retValue;
			}
			else
				_this.value = retValue;
			var frame;
			while (frame = (targetFrames || _this.topFrames).shift()) { // iterate through all the resulting threads/frames
				// This is the beginning of a resume
				currentThread = {};
		//		checkRestState();
//				if (!frame._r) 
	//				throw new Error("Future called without being in a result state");
				frame.retValue = retValue;
				if (frame.NRY)
					frame.thread = currentThread;
				while (frame.parentFrame) {
					frame = frame.parentFrame; // now the bottom frame
					frame.thread = currentThread;
				}
				if (frame.args) {
					suspendedFrame = frame; // the .parents indicates it was a NotReadyYet function, so there is no suspended frames above it
					pjs.transaction(frame.args.callee,frame.frameThis,frame.args,frame.transaction || (frame.transaction = {rollbacks:[]}));// now resume
				}
				else {
					//A thread was resumed with no call stack
					suspendedFrame = null;
				}
			}
		}
						
		if (func) {
			if (callback)
				this.addListener(callback);
			pjs.transaction(function() {
				var f = _frm(arguments);
				var value = func.apply(thisObj || window,args||[]);
				if (value===_S) return f.sus();
				_this.fulfill(value);
			});			
		}
	}
	Future.prototype = {
		addListener : function(func) {
			push(this.topFrames,func);
		},
		interrupt : function (exc) {
			strands.exception = exc;
			this.fulfill(strands.INTERRUPTED);
		},
		isDone : function() {
			return this.hasOwnProperty('value');
		},
		result : function(timeout) {
			if (this.hasOwnProperty('value') || (suspendedFrame && suspendedFrame.retValue)) { // The future has been called, we can resume
				var value = (suspendedFrame ? suspendedFrame.retValue : 0) || this.value;
				suspendedFrame = null; // make sure we don't get any callers picking this up, we may not need this
				if (value == strands.TIMEOUT || value== strands.INTERRUPTED) {
					value = strands.exception || value;
					delete strands.exception;
					throw value;
				}
				return value;// the event future has already been called so we can just return the result
			}
			var topFrame = {}
			push(this.topFrames,topFrame);
			var _this = this;
			topFrame.args = [];
			topFrame.args.callee=function() {return _this.result()};
			suspendedFrame = topFrame;
			if (timeout) {
				var _this = this;
				setTimeout(function() {
					_this.fulfill(specificNotify = {retValue:strands.TIMEOUT,targetFrames:[topFrame]});
				},timeout);
			}
			return Suspend;
		}
	}

	var CallFrame = function() {
	}
/*	_is = function(instance,schema) {
		var myStruct=instance._schema;
 		return myStruct && (myStruct == schema || schema.isPrototypeOf(myStruct));
	};*/
	var Construct;
	var defaultScope = CallFrame.prototype = {
	sus : function() { 
				var al= arguments.length;
				for (var i = 0; i < al-2;i++) // record all the vars and params 
					this[i] = arguments[i];
				if (al > 1)
					this.cp = arguments[al-2]; // record the code pointer
				this.frameThis = arguments[al-1]; // record the code pointer
				if (suspendedFrame == this)
					same;
				if (!suspendedFrame)
					NoSuspendedFrame; // This can be caused by returning Suspend without actually being in a suspension, or if _S ends up in a variable
				suspendedFrame.parentFrame = this;
				
				this.childFrame = suspendedFrame; // it needs to be reexecuted
				suspendedFrame = this;
				if (this.thread == currentThread) // Assertion
					SuspensionFrameShouldNotBeCurrentThread;
				return Suspend;
			},
		exc : function(exception) {
			if (!this.ecp)
				throw exception;
			this.thr = true;
			this.ex  = exception;
			return this.ecp;
		},
		clsr : function(func) {
			if (this.scp)
				this.inner = func;
			return this.inner;
		},
		scp : 2,
	
		keys : function(obj) {
			var keys = [];
			if (obj._lengthLoaded)
				if (Array.forEach(obj,function(){}) == Suspend) return rerunLater(this,arguments);
			for(var n in obj) 
				push(keys,n);
			return keys;
		},
		Suspension : _S = Suspend,
			
		_new : function(value,args) { // create a new instance of an object or constructor
			if (value === Suspend)
				return value;
			var _f = _frm(arguments);				
			if (!_f.cp) {
				_f.cp=1;
				_f.Const= value;
				Construct = function(){};
				Construct.prototype = value.prototype;
				if (value === String || value === Number) // these classes must not have a target this
					return args.length?new value(args[0]):new value;
				if (value !== Date) { // date does not have to directly instantiated, but it does need an undefined scope, it also needs to be able to handle variable arguements
					_f.newThis = new Construct();
				}
			}
			if ((value = _f.Const.apply(_f.newThis,args?args:[])) == Suspend) return _f.sus();
			if (value instanceof Object) return value; // if the new returns a different value than "this"			
			return _f.newThis;
		}
	}
	
	/**
	 * Suspend execution for the given amount time
	 * @param time	milliseconds to pause
	 */
	sleep = function(time) {
		var _f = _frm(arguments);
		if (!_f.cp) { // if it is zero
			_f.cp = 1;
			setTimeout((_f.future = new Future).fulfill,time);
			_f.future.result();
			return _f.sus();
		}
		_f.future.result(); // this is the wait operation to resume
	}
	
	var rerunLater = function(_this,args) {
			// If a rerunnable function calls a strands function in needs to call this after a strands frame suspends. This will make it so there will not be a reference to this frame and it will not be required to be executed
			var susFrame = suspendedFrame;
			suspendedFrame = null;
			var f = _frm(args);
			suspendedFrame=susFrame; // don't resume this frame
			f.sus(this);
			delete f.childFrame;
			f.NRY = 1;
			return Suspend;
		}
	strands = { // TODO: All the strands stuff should go in here
		rerunLater : rerunLater,
		clearSuspension : function() {
			suspendedFrame = null;
		},
		/**
		 * This function that will be called to return a function that should execute the provided function in order to initialize the stack 
		 * Any time a new stack is created, the returned function will be used. This provides a mechanism to wrap all processing
		 * within a try catch.
		 */
		errorWrapper : function(func) {
			var newFunc = function() {
				if (debugMode)
					return func.apply(this,arguments);			
				try {
					return func.apply(this,arguments);			
				}
				catch (e) {
					alert(e.message || e);
				}
			}
			newFunc.noTryCatch = func;
			return newFunc;
		},
		js17 : window.Iterator && {}.__defineSetter__,
		compilerUrl:'js/compiler.js',
		TIMEOUT : {toString:function(){return "Thread timeout"}},
		INTERRUPTED : {toString:function(){return "Thread interrupted"}},
		sleep : sleep,
		/**
		 * This is a constant that is returned from functions to indicate that the code execution is suspending
		 */
		Suspension : Suspend		
	}
	var coreturn;
	var strandSrc="strand=function(func) {\n"+  // this function is considered invalid syntax so it must be evaled only for js17 environments
"return function() {\n"+	
"			if (suspendedFrame && suspendedFrame.thread == currentThread && suspendedFrame.args && !suspendedFrame.NRY) {\n"+
"				var frame = suspendedFrame;\n"+
"				suspendedFrame = frame.childFrame;\n"+ // if this is undefined it means we are at the top of the resume stack
"				delete frame.thread;\n"+
"				delete frame.childFrame;\n"+// for assertions
"				var result = suspendedFrame.args.callee.apply(this,suspendedFrame.args);\n"+ // resume the stack
"				if (result == Suspend) return CallFrame.prototype.sus.call(frame,this);\n"+ // if we have to suspend again right away
"		}\n"+
"		else {\n"+ //fresh entry
"			var frame = func.apply(this,arguments);\n"+
"			if (!(frame != null && typeof(frame) == 'object' &&\n"+
"					typeof(frame.next) == 'function' && typeof(frame.send) == 'function'))\n"+
"				return frame;\n"+
"			frame.args = arguments;\n"+
"			var result;\n"+
"		}\n"+
"		try{\n"+
"			while(1){\n"+
"				coreturn = undefined;\n"+ // global return value
"				result = frame.send(result);\n"+
"				if (result && result._notReady) result = loadProp(result);\n"+ 
"				if (result == Suspend) return CallFrame.prototype.sus.call(frame,this);\n"+
"			} \n"+
"		} catch(e if e == StopIteration) {\n"+
"			return coreturn;\n"+
"		}\n"+
"	}\n"+
"}";
strand = strands.js17 ? eval(strandSrc) : function() {throw new Error("can not call strand except as a function wrapper");};	/** 
	 * This creates a new Strands call frame. It becomes the scope for the function maintains variables and parameters across suspensions and resumes. It should only be used in compiled code
	 */	
	_frm = function(args) {
		if (args.caller) args.caller=0; // this fixes a big memory leak;
		if (suspendedFrame) {
			// if it is loading we start a new frame
			if (suspendedFrame.thread == currentThread && suspendedFrame.args && !suspendedFrame.NRY) {// this means we are resuming
				var frame = suspendedFrame;
				//TODO: Implement this:
				if (frame.args.callee != args.callee && frame.args.callee.toString() != args.callee.toString()) {// this means the function that is being called has changed, the function has been replaced, so we need to call the orginal one
	//				if (this!=frame.frameThis) {
						suspendedFrame = null;
						StackAlterationError("The function has changed, the means for handling this right now is not complete");
		//			}
/*					var retValue = frame.args.callee.call(frame.frameThis);
					if (retValue == _S){
						// this is the tricky part, we need to call the next function and have it be guaranteed to return a _S
					}
					else {// we need to come up with a way to ensure that we have the right rv#
						frame["rv" + frame.cp++] = retValue;  //make sure we increment the cp so we are the next part
					}
					return frame;*/
				}
				delete frame.thread;
	
				suspendedFrame = frame.childFrame; // if this is undefined it means we are at the top of the resume stack
				delete frame.childFrame; // for assertions
				if (suspendedFrame && suspendedFrame._r) {//Assertion stuff
					if (! suspendedFrame.parentFrame)
						SuspendedFrameHasNoParentFrame;
					else
						delete suspendedFrame.parentFrame;				
				}
				for (var i =0;i<frame.args.length;i++)
					args[i] = frame.args[i];
				frame.scp=0; // start in the suspend segment
				return frame;
			}
			else { // this case means that there is a suspendedFrame variable left over from a previous resume/suspension
				// It should only be a left over from a suspension, and it should be the bottom frame.  A resume should null out suspendedFrame
	
				suspendedFrame = null;  // a suspension took place somewhere else, so now we can get rid of this
			}
		}
		frame = new CallFrame;
		frame.scp = 1; // Why is this needed for opera to work? somewhere the prototype cp is getting set, need to figure out why
		frame.args = args;
		return frame;
	}
	function Generator(frame){
		this.frame = frame;
	}
	Generator.prototype = {
		next : function() {
			return this.send();
		},
		send : function(value) {			
			suspendedFrame = this.frame;
			suspendedFrame.thread = currentThread;
			_receive = value;
			return this.frame.args.callee.call(this.frame.frameThis);			
		}
	} 
	_gen = function(frame) {
		return new Generator(frame);
	}
	returns = function(value) {
		coreturn = value;
		throw StopIteration;
	}
    var get,set;
	var dataTable = pjs.dataTable = {
		jsponField:{
			schema: {
				type : { name:"type",type:"any"},
				name : {name:"name",type:"string"},
				description : {name:"description",type:"string"}
			}
		},
		defaultScope:defaultScope
	};
	var userData = Suspend;
	var getUserData;
	var monitoredObjects = {};
	var currentTransaction = null;
	pjs.writeInProgress = function() {
		return !(!currentTransaction);
	}
	if (!window.util)
		util = {};
	/** Read a cookie with the given name
	 * @param name 	name of the cookie to read
	 * @return	the value of the cookie
	 */
	readCookie = function(name) {
			var nameEQ = name + "=";
			var ca = document.cookie.split(';');
			for(var i=0;i < ca.length;i++) {
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (!c.indexOf(nameEQ)) return c.substring(nameEQ.length,c.length);
			}
		}
	createCookie = function(name,value,days) { 
			if (days) {
				var date = new Date(new Date().getTime()+(days*24*60*60*1000));
				var expires = "; expires="+date.toGMTString();
			}
			else 
				expires = "";
			document.cookie = name+"="+value+expires+";path=/";
			if (value && (readCookie(name) != value))
				alert("cookie could not be set" + readCookie(name)  + "!=" +  value);
		}
	evaler = strands.errorWrapper(evaler);
	var pendingAsynchCalls = 0;
	var requestData;
	function getProto(obj) {
		if (obj.hasOwnProperty('constructor')) {
			var objConst = obj.constructor;
			delete obj.constructor;
			var rv = obj.constructor.prototype;
			obj.constructor = objConst;
		}
		else
			rv = obj.constructor.prototype;
		if (rv != Object.prototype && rv != Array.prototype)
			return rv;
//		return obj.__proto__ == Object.prototype || obj.__proto__ == Array.prototype ? undefined : obj.__proto;
	}
	var NotReadyField={_notReady:1};
	var NotReadyYet = function(object) {
		return function() {
			var args = arguments;
			if (suspendedFrame && suspendedFrame.args && suspendedFrame.args.callee._notReady && suspendedFrame.thread == currentThread) {// if it resumes because another function has a handle on it then we need to make we remove the suspended frame the first time but not subsequent times
				args = suspendedFrame.args; // we need to get the arguments
				suspendedFrame = null; // this means that the function is the bottom of the stack
			}
			var object = arguments.callee;
			if (typeof object._notReady != 'function') { // this indicates we are not ready
				if (requestData(object)===Suspend) { //,object._notReady?null:"psv15"
					var frame = suspendedFrame;
					frame.args = args; // save the arguments
					frame.frameThis = this; // and this
					frame.NRY=1;
					return Suspend;
				}
			}
			return object._notReady.apply(this,args);

		}
	}
	var incompleteRequests={};
	var incompleteQueue = [];
	var currentRequestValidAsOf;
	var validAsOfTable={};
	
	var accessLevel={};
	var defaultAccess = 2;
	var delayIntake = function(dependent,data,id) {
		var changeId = dependent._id;
		data._sourceUrl = sourceUrl; // record this so we can reenter the right sourceUrl
		var otherDependent;
		while ((otherDependent = incompleteRequests[changeId]) && (otherDependent.id != changeId && otherDependent.id != id)) {// we can chain from the one that is going to be performed when ours is completed
			changeId=otherDependent.id; 
		}
		incompleteRequests[changeId]=data;
		incompleteQueue.push(changeId);
		return dataTable[id] = {_id:id,_notReady:1};			
	}

	var intake = function(data,aliasId) {
		if (typeof data != "object" || data === null) {// we don't need to process primitives
			if (typeof data == "string" && (id=data.match(/([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z$/)))
				return new Date(new Date(id[1],id[2]-1,id[3],id[4],id[5],id[6]).getTime() - new Date().getTimezoneOffset() * 60000);
			return data;
		}
		var id = data.id || data.$ref;
		if (aliasId && !aliasId.match(/^t\$/))
			delete aliasId;
		var ready;

		if (!id && aliasId) {
			id = aliasId;
			ready=true;
		}
		else if (id===undefined) { // even if it is not persistent it may have children that are POs that need parsing
			if (data.ready === 0)
				return NotReadyField;
			if (data instanceof Array) {
				var obj = [];
				for (var field in data)  		// iterate through fields and array entries to parse them and augment a primitive
					obj[field] = intake(data[field]); 
				return obj; 
			}
		}
		else {
			if (id.charAt(0)=='.' && id.charAt(1)=='.')  //TODO: make this be able to go multiple levels
				id = sourceUrl.match(/(.*?)(\w*\/$)/)[1] + id.substring(3);
			else if (id.match(/local:\/\//)) // this means a foreign domain has made a reference back to the primary domain data				
				id = id.substring(8); 			
			else if (!id.match(/http:\/\//))
				id = sourceUrl + id; // inherit the current sourceUrl
			obj = dataTable[id];
			ready = obj && !obj._notReady;
		}
		var basis;
		if (obj == undefined && aliasId && (basis=dataTable[aliasId])) { 
			obj = basis;
		}
		if (data.requires && (basis = intake(data.requires))._notReady) {
			if (!obj) 
				obj = delayIntake(basis,data,id);					
			return obj;
		}			
		if (data['function'] && (!obj || (obj._notReady && data.psv15))) { // this should actually go after basis
			var oldFunc = obj;
			obj = data.psv15;
			if (obj) { // TODO: check to see if it already exists
				if (typeof obj == "string") 
					obj = evaler(obj,"function:"+id); // if in eval is done directly here, it will break Opera.  Doing it this way also does less scope holding, and prevents memory leaks
				if (!obj)
					obj = function() { throw new Error("There was a syntax error in this function")};
				if (oldFunc) {
					for (var i =0; i < oldFunc._notReady.length; i++) {
						var parent = oldFunc._notReady[i];
						for (var j in parent)
							if (parent[j] === oldFunc) // replace all the instances of this function
								directSet(parent,j,obj);								
					}
					oldFunc._notReady = obj; // this is it's replacement
				}		
				//ready = true;
			}
			else if (!obj) {
				obj= NotReadyYet();
				obj._notReady = [];
			}
		}
		else if (data.basis) {
			basis = intake(data.basis, ((obj||0).basis||0)._id);
			if (!obj || basis !== getProto(obj)) {
				if (basis._notReady) {
					if (!obj) 
						obj = delayIntake(basis,data,id);					
					return obj;
				}
				var ready = obj;
				obj = pjs.newInstance(basis);
				ready =0;
			}
		}
		if (!obj) {
			if (data instanceof Error) return data; // TODO: remove this when RPC error reporting solution is in place
			obj = (data.array || data instanceof Array)?[]:{};
		}
		if (id) {
			obj._id = id;				
			dataTable[id] = obj;
		}
		if (data.schema) // TODO: use directSet?
			obj._schema = intake(data.schema,(obj._schema||0)._id); // we want to go around the schema stuff
		for (var field in data) {
			var value = data[field];
			if (field !="function" && (field != "array" || data.array.ready!==0))
				ready = true;
			switch (field) {
				case "id" :  // we must cycle through all the known ones
				case "$ref" : break;
				case "ready" :
					if (!value)
						delete ready;
					break;
				case "array" : // bring in all the array data
					if (typeof data.ready== 'string') {// it means it is a range hopefully
						if (ready = data.ready.match(/([0-9]+)-([0-9]*)/)) {// get the range, if there is no match than we just treat it like a normal array
							var startingIndex = 1*ready[1]; 
							if (ready[2])
								obj._lengthLoaded = 1*ready[2] + 1;
							else
								delete obj._lengthLoaded; // we are at the end of the list
						} 
					}	
					else {
						startingIndex = 0;
						delete obj._lengthLoaded;
					} 
					if (value instanceof Array) {
						for (var field in value)
							if (!isNaN(field)) 
								directSet(obj,1*field + startingIndex,intake(value[field],id + '[]' + 1*field + startingIndex + ']'),1);
					}
					else if (value.ready !== 0){ // transposed array
						for (var field in value) {
							var col = value[field];
							var item = obj[field] || (obj[field] = {});
							if (col instanceof Array) {
								for (var i in col)	
									if (!isNaN(i)) 
										directSet(item,1*i + startingIndex,intake(col[i]),1);
							}
							else { // TODO: this should actually run after the arrays have been run so that the correct number of columns are avialbale 
								for (var i = 0; i < obj.length; i++)
									obj[i] = col;								
							}
						}
					}							
						/*if (value instanceof Array) {
						if (isIE && obj.__proto__)
							obj._ieLength = value.length;
						else
							obj.length = value.length;
					}*/
					break;
				case "psv15" : break;	// TODO: we need to be able handle when this is a function but this compilation is not provided
				case "basis" :
					//if (!strands.js17)
						//directSet(obj,'__proto__',basis); // it has already been intaked				
					break;
				case "schema" : break;
				default :
					if (typeof value == "object" || typeof value == "string")  // guard the calls to intake to improve performance
						value = intake(value,(obj[field]||0)._id||(id+'.' + field));		// if it is the basis it should already have been processed
					if (field.substring(0,8) == "public::")
						field = field.substring(8);
					directSet(obj,field,value);
			}
		}
		
		if (ready) {
			if (!obj.getter && !obj.setter) {
				delete obj.__key;
				delete obj.__parent;
				delete obj._notReady;
			}
			else	
				obj._notReady=1;
			validAsOfTable[id] = currentRequestValidAsOf;
			if (!accessLevel[id])
				accessLevel[id] = defaultAccess; // if it is not specified use the default access for this transfer
			//currentRequest += id+",";
			if (basis = incompleteRequests[id]) { // we can resolve the incompleteRequests now
				delete incompleteRequests[id];
				var oldSourceUrl = sourceUrl;
				sourceUrl = basis._sourceUrl;
				delete basis._sourceUrl;
				intake(basis);
				sourceUrl = oldSourceUrl;
			}
		}
		else
			obj._notReady=obj._notReady||1;
		return obj;
	}
	pjs.hostForId = function(id) {
		if (id.indexOf("http://"))
			return '';
		else
			return id.substring(0,id.indexOf('/',8)+1); // http request
	}
	var messagesLastChecked=0;
	var lastDataReceived;
	var currentRequests = {};
	var usernames = {};
	var sourceUrl;
	var rpcStacks={};
	var rpcsToBeSent=[];
	
	var RequestFulfilled = {}; 
	/**
	 * This loads the data from the JSON data received from a server
	 */
	var loadData = function(requestName, responseObject,headers) {
		pendingAsynchCalls--;
		if (pendingAsynchCalls <= 0) {
			pendingAsynchCalls = 0;
			if (pjs.status)
				pjs.status();
		}
		currentRequestValidAsOf = (headers && Date.parse(headers.Date)) || 1; // if none is provided still set the value
		function fulfillRequest() {
			if (typeof currentRequests[requestName] == 'function') {
				var currentRequest = currentRequests[requestName];
				currentRequests[requestName] = RequestFulfilled;
				currentRequest(lastDataReceived);	
			}
		}
		function loadedObject() {
			return dataTable[requestName.replace(/(\.[^\/]*)$/,'')]; // remove the trailing field parameter
		}
		var url = requestMap[requestName] || requestName;
		sourceUrl = requestName.substring(0, requestName.lastIndexOf('/') + 1);
		var obj,access;
		if (headers && headers['Access-Level']) {
			eval('access='+headers['Access-Level']);
			for (var i in access) // read in all the access levels.
				accessLevel[sourceUrl + i] = access[i];
			if (!access.username)   // if there is no username, make sure we delete our Authorization cookie, so we don't think we are logged in
				createCookie(sourceUrl + 'Auth','',-1);
			
			defaultAccess = access['default'] || 2;
		}
		else 
			defaultAccess = 5; 
		if (!responseObject || responseObject.id===undefined) {// if it is unidentified object/primitive that is coming across than create an object for it to read in
			if (obj = loadedObject()) {  // this indicates that it is a field
				obj = {id:obj._id};
				sourceUrl = ""; // it is included in the id now
				obj[requestName.replace(/(.*)\.([^\/]*)$/,'$2')] = responseObject;
				responseObject = obj;
			}
		}
		if (responseObject && responseObject.id && responseObject.error !== undefined && responseObject.result !== undefined) { 
				var id = responseObject.id;
				delete responseObject.id; // must remove it for intake
				rpc = intake(responseObject);
				if (rpc.method){
					try {
						var rpcResponse={id:id,result:exportable(rpc.object[rpc.method].apply(rpc.object,rpc.params))};
					}
					catch(e) {
						rpcResponse={id:id,error:e.message};
					}
					persevere.request(sourceUrl,rpcResponse); //TODO: return a response
				}
				else {
					rpc.error ? rpcStacks[id].interrupt(new Error(rpc.error)) : rpcStacks[id].fulfill(rpc.result); 
				}
		}
		else 
			lastDataReceived = intake(responseObject,url); // This is a little brittle because a host could return a value that is not rooted with the requested value
		if (!dataTable[url])
			dataTable[url] = lastDataReceived;
		if (obj = loadedObject()) {
			if (obj._notReady && !(obj.getter || obj.setter)) {
				if (obj.access === 0)
					throw new Error("Access denied to " + requestName); 
				else {
					if (!incompleteQueue[0])
						throw new Error("Requested object was not returned " + requestName); // TODO: I don't think it is possible to get to this point, might want to remove this
				}
			}
			while (incompleteQueue.length) {
				requestName = incompleteQueue.shift();
				if (!currentRequests[requestName]) {
					requestData(requestName);
					suspendedFrame = null;
					break;
				}
			}
		}
		else
			fulfillRequest();
		
		for (requestName in currentRequests) { // go through all the currentRequests and if it has been satisfied then resume the waiting thread
			if ((obj=loadedObject()) && (!obj._notReady || obj.getter || obj.setter)) 
				fulfillRequest();
		}
	}

	/*This sections handles loading data from the AJAX requests */
//	currentExecutor = undefined;
	var callRequestId = 0;
	
	var getXMLHttpRequest = function () {
		if (parent.XMLHttpRequest)
	        return new parent.XMLHttpRequest();
		else if (window.ActiveXObject)
	        return new ActiveXObject("Microsoft.XMLHTTP");
	}
	var responseError;
	var autoSave;
	var requestMap ={};
	/**
	 * Makes a request from the given url
	 * @param url - url to request
	 */
	var request = function(url,parameters,operation, body,aliasId,asText) {
		var frame=_frm(arguments);
		var synchronousCall = pjs.synchronousMode;
		parameters = parameters || {};	
		function reqString() {
			var reqString = "";
			for (var i in parameters)
				reqString += (reqString?"&":"") + i + "=" + encodeURIComponent(parameters[i]);
			return reqString;
		}
		if (operation) {
			var requestName = url.replace(/[^\/]*$/,'') + "c" + callRequestId++; // keep the right relative path
			requestMap[requestName] = aliasId;
		}
		else
			requestName = url;
		
		if (frame.future || typeof currentRequests[requestName] == 'object') {// this means we are resuming
			if (responseError) {
				delete currentRequests[requestName];
				var message = responseError;
				responseError =0;
				throw new Error(message);
			}
			if (frame.future)
				return frame.future.result();  // this is called to get the return value
		}
		var future = frame.future = new Future();
		var wait = function() {
			future.result();
			return frame.sus();
		}
		if (currentRequests[requestName]) {
				var lastCallback = currentRequests[requestName];
				currentRequests[requestName] = function () {
					if (typeof lastCallback == "function")
						lastCallback();
					future.fulfill();
				};

				return wait();
		}
		else {
			// show the loading status
			var noResponse = function(statusCode,message) {
				if (statusCode == 401)
					responseError = "Access was denied";
				else
					responseError = message || "There was no response from the server for " + requestName + ", the connection may have been lost. " + (statusCode?"status code is: " + statusCode:"");
				loadData(requestName);
				responseError =0;
			}
		    pendingAsynchCalls++;
		    var crossDomain = url.substring(0,7) == "http://";		    
		    var ticket = readCookie(pjs.hostForId(url) + "Auth");
			if (ticket)
			    parameters.Auth = parameters.Authorization = ticket; // need Auth because of a bug in IE
		    if (pjs.status)
		    	pjs.status((!operation?"loading":operation<3?"saving":operation) + "...");
			//TODO: make this a static function
			currentRequests[requestName] = function() {}; //This needs to be here because IE can do an inline request handle for ajax calls 
			if ((isIE || !debugMode || asText || operation || synchronousCall) // all reasons we don't need use a script tag!  
				&& !crossDomain) { 
			 	var xhr = getXMLHttpRequest();
				var ajaxDataReader = function () {
					if (xhr.readyState == 4) {// only if "OK"
				        var loaded;
				        try {
				        	var status = xhr.status;
							var data = xhr.responseText;
				        	loaded = status == 200 && data.length > 0;//firefox can throw an exception right here
				        } catch(e) {}
				        if (loaded) {
				        	var contentType = xhr.getResponseHeader("Content-Type");
				        	if (!(contentType == "text/html" || contentType == "text/css" || asText))
					        	var data = evaler(data,"id:" + requestName); // I don't know why this has to be as a two step process, but it seems to be the only way it work right all the time.
							loadData(requestName,data,{"Access-Level":xhr.getResponseHeader("Access-Level"),Date:xhr.getResponseHeader("Date"),RPCs:xhr.getResponseHeader("RPCs")});
						}
						else
							noResponse(status,data);
			        	xhr = null; // This is to correct for IE memory leak
					}
				}
			    xhr.open(operation ? operation == 2 ? "PUT" : "POST" : "GET", // if it is loading, it should have no side effects, so we can use a GET
			    						url, !synchronousCall);
				for (var i in parameters)
					xhr.setRequestHeader(i, parameters[i]);

//			    if (operation==1)
	//		    	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");
			    if (!synchronousCall)
					xhr.onreadystatechange = ajaxDataReader;
				//TODO: only do _clientSession if it is a get and there is a refresh cookie value (need to put a refresh in a saving operation)
			    xhr.send(body);
			    if (synchronousCall)
			    	ajaxDataReader();
			}
			else { 
			    dataLoaded[requestName] = function(data,headers) {	
			    	loadData(requestName,data,headers);
			    }
				var postResponse;
				if (operation) { // use the post form method for cross domain POST operations
				    var iFrame = document.body.appendChild(document.createElement("iframe"));
				    iFrame.style.width="1px";
					iFrame.style.height="1px";
						var iframeWin = iFrame.contentWindow;
						try {
					    var doc = iframeWin.document;
						} catch (e) {
							return alert("Iframe could not be created. This is a known issue with safari. Please try your action again");
						}
						doc.open();
						doc.write("<html><body><form method='POST' id='f'>this is my form</form></body></html>");
						doc.close();
					    var formElement = doc.getElementById('f');
					    formElement.action =  url;
					    postResponse = parameters.PostResponse = new Date().getTime();
					    for (var i in parameters) {
						    var inputElement = formElement.appendChild(doc.createElement("input"));
						    inputElement.name = i;
						    inputElement.value = parameters[i];
					    }
						parameters = {PostResponse:postResponse};
					    formElement.submit();
				}
				// use the script tag method 
				parameters.callback = "pjs.loaded('" + requestName.replace(/('|\\)/g,'\\$1') + "')";
				var sendData = reqString();
				if (sendData)
					url += "?" + sendData;
			    var scriptTag = document.createElement("script"); // must use the document that supports events, not his one
			    scriptTag.setAttribute("src", url);
			    document.body.appendChild(scriptTag); // This is supposed to be asynchronous, but sometimes it will get its request before continuing			    
			    setTimeout(function() {
			    	if (currentRequests[requestName] != RequestFulfilled) {
						noResponse();
			    	}
			    },30000); // 30 second time out
			}
			if (currentRequests[requestName] == RequestFulfilled)  // it is already fulfilled
				return lastDataReceived;
			else { // it is being done asynchronously
				currentRequests[requestName] = frame.future.fulfill;	
				return wait();
			}
		}
	}
	persevere = {
		getProto : getProto,		
		request : function(url,parameters,operation) {
			for (var i in parameters)
				parameters[i] = JSON.stringify(exportable(parameters[i]));
			return request(url,parameters,operation);
		},
		compilerUrl : 'js/compilers',
		setAutoSave : function(value) {
			if (strands.js17 || !value) // if we are turning it off or using js17 mechanism
				_p = function(obj,field,value) {
					return obj[field]=value;
				}
			autoSave = value;	
		},
		/**
		 * Loads the given script. It will compile the script if necessary for lazy loading
		 * and coroutine support. 
		 * You can set persevere.precompiled = true if the scripts have
		 * been precompiled on the server. It is HIGHLY recommended
		 * that you compiled the scripts on the server to reduce the overhead
		 * on the client. 
		 * @param {Object} url
		 */
		loadScript : function(url) {	
			var frame = _frm(arguments);
			switch(frame.cp) {
				case undefined:frame.future = new Future();
					frame.url = url;
					frame.cp = 1;
				case 1: case 2:case 3:url = frame.url;
				var compOptions;
				if (url.match(/\.pjs$/)) 
					compOptions = {setters:true};
				else if (url.match(/\.js17$/)&& !strands.js17) 
					compOptions = {source:'js17',setters:autoSave};
				
				if (persevere.precompiled && !(url.match(/\.js17$/)&& strands.js17))
					url = url.replace(/\.[^\.]*$/,'.js');
				else
				{
					if (compOptions) {
						if (!strands.compiler || frame.cp == 2) {
							frame.cp = 2; 
							if (pjs.load(strands.compilerUrl)==Suspend)
								return frame.sus();
							frame.cp = 3;
							compOptions.getters=true;
							strands.compiler = new StrandsCompiler(compOptions);
						}
						var source;
						if ((source = request(url,0,0,null,null,1))==Suspend)
							return frame.sus();
						source = strands.compiler.compile(source);
					}
				}
				if (!source) {
					if (strands.js17) {
						if (frame.cp != 2) {					
							persevere.js17AutoSet = 1;
						    var scriptTag = document.createElement("script"); // must use the document that supports events, not his one
						    scriptTag.onload = frame.future.fulfill;
						    scriptTag.type= 'application/javascript;version=1.7';
							scriptTag.setAttribute("src", url);
						    document.body.appendChild(scriptTag); // This is supposed to be asynchronous, but sometimes it will get its request before continuing
					    }
						frame.cp = 2;
					    return frame.future.result()==_S?frame.sus():0;
				    }			    
					else 
						if ((source = request(url,0,0,null,null,1))==Suspend) return frame.sus();					
				}
				if (window.execScript)
					execScript(source);
				else
					setTimeout(source,0);

			}
		},
		init : function(obj){sourceUrl='';return intake(obj)},
				/**
		 * This function will return a function that will execute the given method from the prototype of the object
		 * that refers to the currently executing method.
		 * @param {Object} methodName
		 * @return {Function} super function (with proper scoping)
		 */
		superCall : function(_this,args,methodName) {
			var func = args.callee;
			var basis = _this;
			var found;
			do {
				if (basis[methodName] == func || (basis[methodName] && basis[methodName].toString() == func.toString())) // TODO: This is necessary because of the possibility of overwriting functions intake.  We may want to change that...
					found = 1;
				else if (found) {
					function callSuper() {
						return basis[methodName].apply(_this,arguments);
					}
					return callSuper;
				}
			}while (basis = getProto(basis));
			throw new Error("This function does not have a super/basis object to call");
		},
		rpc : function(thisObj,args,method,callback) {
			var _f = _frm(arguments);
			if (!_f.future) {
				rpcCommit=1;
				pjs.commit();
				rpcCommit=0;
				if (!method) 
					for (var i in thisObj)
						if (thisObj[i] == args.callee) {
							method = i;
							break;
						}
				_f.future = new Future;
				rpcStacks[_f.id = _f.id || seqId] = _f.future;				
				request(thisObj._id,{"Seq-Id":seqId++},1,JSON.stringify({method:exportable(method || args.callee),params:exportable(args,true),id:_f.id}),thisObj._id + 'rpc' + _f.id);
			}
			var rv = _f.future.result();
			if (rv == _S) return _f.sus(this);
			if (callback) callback(rv);			
			return rv;
		}
	}
	
	requestData = function(objectOrId,field) {
		objectOrId = objectOrId._id || objectOrId;		
		if (objectOrId.substring(0,7) == "client/")
			error("Can not request client data from the server");
		if (field) 
			objectOrId += "." + field;
		return request(objectOrId);
	}
	function accessDenied(obj,writing) {
		if(pjs.accessDenied)
			return pjs.accessDenied(obj,writing);
		var username = pjs.getUserName(pjs.hostForId(obj._id));
		if (!username) 
			pjs.authenticate(prompt("Please login. Enter your username: ","username"),prompt("Please login. Enter your password: ","password"));
		else		
			throw new Error("You do not have access to " + (writing?"write to" : "read from") + " this object " + obj.toString("name"));
	}
	
	var getId = pjs.getId = function(object) {
		if (object.getElementsByTagName)
			return object._id || (object._id = "client/" + Math.round(Math.random()*10000000000));
		return object.hasOwnProperty("_id")?object._id:(object==Object.prototype||object==Array.prototype)?"proto":object._id="client/" + Math.round(Math.random()*10000000000);
	}
	
	var reservedWords = ["id","ready"];
	var objectsBeingPersised= {};
	var isPersisted = pjs.isPersisted = function(object) {
		return typeof object._id == 'string' && object.hasOwnProperty("_id") 
		&& (object._id.substring(0,7) != "client/" || objectsBeingPersised[object._id]);
	}
	var exportable = function(object,mode,sourceUrl) { // mode 0 = standard, mode true = direct array, mode number = updating object
		if (object instanceof Date) {
	        function f(n) {
	            return n < 10 ? '0' + n : n;
	        }
	        return object.getUTCFullYear() + '-' +
	                f(object.getUTCMonth() + 1) + '-' +
	                f(object.getUTCDate()) + 'T' +
	                f(object.getUTCHours()) + ':' +
	                f(object.getUTCMinutes()) + ':' +
	                f(object.getUTCSeconds()) + 'Z';
		} 
		if (object && (typeof object == "object" || typeof object == "function")){ // TODO: we may also want to consider the case of a non-persistent function
			var transferObject = {};
			if (mode===true) {
				/*delete object.update;*/
				transferObject = [];
				for (var i=0; i < object.length; i++)
					transferObject[i] =  exportable(object[i]);
				return transferObject;
			}
			var id = getId(object);
			var local = id.substring(0,7) == "client/";
			if (sourceUrl)	 
				id = id.indexOf(sourceUrl)==0?id.substring(sourceUrl.length):
					id.indexOf('http://')==0?id:'../'+id; // TODO: need to figure out how many directories to move up											
			if (!(mode > 9)&& !local) {// unless it is a brand new persistent object, then it needs to be create so we will just leave it alone										
				return {$ref:id}; // make this into a reference;
			}
			else	{ // the object has not been persisted yet
				dataTable[object._id] = object;
				if (local) {
					objectsBeingPersised[object._id]=trans||1;
				}
				var transferObject = object._isUpdate?{}:{id:id}; // id can be set by getId, so we must refetch id from the object
					var realArray = object.constructor == Array;
					if (realArray)
						transferObject.array=[];
					var stringKeys;
					for (var field in object) {
						if (object.hasOwnProperty(field) && field != '_id' 
							&& !(object._schema && object._schema[field] && object._schema[field]['transient']) &&
							object[field] != pjs.PseudoField && !(object[field] && object[field].getElementsByTagName)) {
							if (strands.js17 && autoSave)
								object.watch(field,watcher);
							var origField = field;
							if (realArray && !isNaN(field)) 
								transferObject.array[field]=exportable(object[field],0,sourceUrl);							
							else {
								switch(field) {
									case "_update": case '_schema':
										field = field.substring(1); break;
									default:  // this should be inlined as well
										if (Array.indexOf(reservedWords,field) != -1) // don't want it to effect update
											field = "public::" + field;								
								}
								stringKeys = true;
								transferObject[field] = exportable(object[origField],object._isUpdate,sourceUrl);
							}
						}
					}
					var proto = getProto(object);
					if (!realArray && proto 
							&& typeof object != 'function' && proto.constructor != object.constructor.__proto__) {// deal with SM's extra prototype chaining on inner functions
						transferObject.basis = exportable(proto,0,sourceUrl);
						stringKeys =true;
					}
					if (realArray && !stringKeys) 
						return transferObject.array;					

//					setTimeout(function() { definedClientObjects = {}},100); // when we are done with the all the recursive exportable we want to clear the define objects
				//}
				delete transferObject._notReady;
				delete transferObject._isUpdate;
				return transferObject; // make this into a reference;
			}
		}
		else if (object instanceof String || object instanceof Number || object instanceof Boolean) // Probably don't need this anymore
			return object.valueOf();
		else if (object === undefined) {
			return {"update":"delete"};
		}
		return object;
	}
	
	JSON = { // TODO: This should be incorporated directly in exportable
	    copyright: '(c)2005 JSON.org',
	    stringify: function (v) {
	        var a = [];
	   		 var m = {
	            '\b': '\\b',
	            '\t': '\\t',
	            '\n': '\\n',
	            '\f': '\\f',
	            '\r': '\\r',
	            '"' : '\\"',
	            '\\': '\\\\'
	        };
	        function e(s) {
	            a[a.length] = s;
	        }
	        function g(x) {
	            var c, i, l, v;
	            switch (typeof x) {
	            case 'object':
	                if (x) {
	                    if (x instanceof Array) {
	                        e('[');
	                        l = a.length;
	                        for (i = 0; i < x.length; i += 1) {
	                            v = x[i];
	                            if (typeof v != 'undefined' &&
	                                    typeof v != 'function') {
	                                if (l < a.length) {
	                                    e(',');
	                                }
	                                g(v);
	                            }
	                        }
	                        e(']');
	                        return;
	                    } 
	                    else if (x instanceof Date) {
	                    	e('"@' + x.getTime() + '@"');
	                    }
	                    else if (typeof x.valueOf == 'function') {
	                        e('{');
	                        l = a.length;
	                        for (i in x) {
	                            v = x[i];
	                            if (typeof v != 'undefined' &&
	                                    typeof v != 'function' &&
	                                    (!v || typeof v != 'object' ||
	                                        typeof v.valueOf == 'function')) {
	                                if (l < a.length) {
	                                    e(',');
	                                }
	                                g(i);
	                                e(':');
	                                g(v);
	                            }
	                        }
	                        return e('}');
	                    }
	                }
	                e('null');
	                return;
	            case 'number':
	                e(isFinite(x) ? +x : 'null');
	                return;
	            case 'string':
		            if (/["\\\x00-\x1f]/.test(x)) {
		                e('"' + x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
		                    var c = m[b];
		                    if (c) {
		                        return c;
		                    }
		                    c = b.charCodeAt();
		                    return '\\u00' +
		                        Math.floor(c / 16).toString(16) +
		                        (c % 16).toString(16);
		                }) + '"');
		            }
		            else
			            e('"' + x + '"');
	                return;
	            case 'boolean':
	                e(String(x));
	                return;
	            default:
	                e('null');
	                return;
	            }
	        }
	        g(v);
	        return a.join('');
	    }
	};
	persevere.stringify = function(value) {
		JSON.stringify(exportable(value));
	}
	var schemas = {};
	typeOf = function(obj) {
		var id = getId(obj);
		var struct;
		if ((obj.hasOwnProperty('_schema') && (struct = obj._schema)) || (struct = schemas[id]))
			return struct; // must check for Suspend
		var basis = getProto(obj);
		struct = schemas[id] = basis ? pjs.newInstance(typeOf(basis)) : {};		
		for (var key in obj) 
			ensureField(struct,key);
		
		return struct;
	}
	var originals={};
	/**
	 * Prepares an object to be modified, recording the original values. When a save is performed, only
	 * the modified properties will be recorded
	 * @param {Object} obj
	 */
	pjs.changing = function(obj) {
		if (isPersisted(obj)) {
			var orig = originals[getId(obj)] = {};
			for (var i in obj)
				orig[i] = obj[i];
		}
	}
	/**
	 * Saves the changes made to a persistent object.
	 * this is not necessary if you using orthogonal persistence and you are only modifying existing properties
	 * @param {Object} obj
	 */
	pjs.save = function(obj) {
		addToTransaction(obj._id,obj,2,function(){});
	}
	pjs.getField = function(obj,field) {
		var struct = typeOf(obj);
		if (isPersisted(struct) && isPersisted(struct[field]))
			return struct[field];
	}
/* This performs a transaction. The first argument "transactionFunction" should execute all of the operations that you want to occur in the transaction.
 * The second argument allows for a callback on success.  If you want to abort the transaction, simply throw an exception and the transaction will be aborted.
 */
	pjs.transaction = function(f,thisObj,args,transToUse) {	 
			var oldTransaction = currentTransaction;
			currentTransaction = (transToUse) ? transToUse : {rollbacks:[]};
			var result;
			if (debugMode)
				result = f.apply(thisObj,args||[]);	// This is a little dangerous because errors don't get caught to eliminate the transaction which results in non-contained writes never being written
			else
				try {
					result = f.apply(thisObj,args||[]);			
				}
				catch (e) {
					alert(e.message || e);
				}
			if (result == Suspend) {
//				suspendedFrame._r.transaction = currentTransaction; // this is done by fulfill and resume
				currentTransaction = oldTransaction;//discard the transaction, i.e. abort or suspend
				return Suspend;
			}
			pjs.commit();
			currentTransaction = oldTransaction;//discard the transaction, i.e. abort or suspend
			return result;
	}
	var rpcCommit;
	var seqId=Math.floor(Math.random() * 100000000);
	/**
	 * This will commit all changes made to persistent objects. The changes will be committed to the JSPON server
	 */
	pjs.commit = function(callback) {
		if (currentTransaction) { // this can be null if a thread was spawned using direct call and that thread was suspended thus nulling the currentTransaction
			if (alertInProgress)
				return setTimeout(pjs.commit,10);
			var rollbacks = currentTransaction.rollbacks;
			for (var id in currentTransaction) 
				if (currentTransaction.hasOwnProperty(id) && id != 'rollbacks') {
					(function(trans,seqId){
						var frm = _frm(arguments);
						var method = trans.method;
						if (method)	 {
							delete trans.object; // this makes it completed
							try { 
								if ((result=request(trans.url,{"Seq-Id": seqId,Commit:!rpcCommit && !currentTransaction.length,"Changes-Since":trans.validAsOf},
										trans.method,trans.body,trans.objId)) == _S) 
									return frm.sus();// we suspend here so that we can resume down below and catch any errors that took place in the save
							}
							catch (e) {
								while (rollbacks.length)
									rollbacks.pop()();
								throw e;								
							}
							if (typeof callback == 'function')
								callback();
						}
					})(currentTransaction[id],seqId++);
					delete currentTransaction[id];
				}
			currentTransaction=null;
		}
	}
	
	/**
	 * This code deals with the problem of setTimeout events occuring during an alert or similiar modal dialog
	 * The commit can happen and it should be delayed
	 */
	var alertInProgress; 
	for (var i in {"alert":1,"prompt":1,"confirm":1}) {
		(function(i) {
			var oldHandler = window[i];
			window[i] = function(a,b) {
				try {
					alertInProgress = 1;
					return oldHandler(a,b);
				}	finally {alertInProgress=0};
			}
		})(i);
	}
	/**
	 * This will undo all the changes to persistent objects since the start of the event or since the last commit
	 */
	pjs.rollback = function() {
		if (currentTransaction) {
			var rollbacks = currentTransaction.rollbacks;
			while (rollbacks.length)
				rollbacks.pop()();
			for (var i in currentTransaction) // would be nice to compact this since this is used in commit as well
				if (i!='rollbacks')
					delete currentTransaction[i];
			currentTransaction = 0;
		}
	}
	
	pjs.authenticate = function(username,password,url) {
		var auth = request((url || pjs.defaultJsponPrefix) + "authenticate",{username:username,password:password},"signing in");
		if (auth != Suspend)  {
			createCookie((url || "") + "Auth",auth,1);			
		}
		return auth;
	}
	function loadProp(value) { //js17 lazy loaded
		if (value._id) {
			if (dataTable[value._id]._notReady)
				if (requestData(value) == _S) return rerunLater(this,arguments);
			if (value.__parent)
				directSet(value.__parent,value.__key,dataTable[value._id]);
			return dataTable[value._id];
		}		
		if (value.__parent[value.__key]._notReady && // we have to see if it got loaded when we resume 
			requestData(value.__parent,value.__key)==_S)return rerunLater(this,arguments);
		return value.__parent[value.__key];
	}
			/** Ensures that an object has been loaded and has loaded parents */
		function ensureLoaded(obj) { // this must stay outside of strands
			if (!obj)
				return;
			if (obj._notReady && !(obj.getter || obj.setter)) {
		 		if (obj.perm === 0)
		 			return accessDenied(obj);
		 		if (requestData(obj) == Suspend) return Suspend;
		 	}
			
			return obj;
		}
		pjs.PseudoField ={};
		function notEqArrays(ar1,ar2) {
			if (!(ar1 instanceof Array && ar2 instanceof Array && ar1.length==ar2.length))
				return true;
			for (var i = 0; i < ar1.length;i++)
				if (ar1[i]!=ar2[i]) return true;			
		}
		function ensureField(struct,key) {
			if (!isNaN(key*1))
				key = 'items';
			if (!struct[key] && key.charAt(0)!='_') 
				struct[key] = pjs.PseudoField;
		}
		
		function nothing() {}
		var directSet = function(target,key,value) {
				if (value === undefined)  {//TODO: we may want to move this out to usage places for better performance so it is not called all the time
						delete target[key];
					if (target._id && changeNotificationList[target._id])
						changeNotificationList[target._id](value);
				}
				else {
					if (typeof value == 'function' && value._notReady)
						push(value._notReady,target);
					if (value) {
						if (value._notReady && target.hasOwnProperty(key) && value._id == target[key]._id)  // trying to load a non loaded value into an already loaded field
							return;
						if (value instanceof String || value instanceof Boolean || value instanceof Number)
							value = value.valueOf();
					}
					var oldValue = target[key];
					if (strands.js17) {
					  	if (value && value._notReady) {
							if (value == NotReadyField)
								value = {_notReady:1};
							value.__parent = target;
							value.__key = key;
					  	}
						watching=0;
						try {target[key] = value}
						finally{watching=1}
						if (autoSave)
							target.watch(key,watcher);
					}
					else
						target[key] = value;
					if (target.hasOwnProperty('_schema')) { // if there is currently a schema than we should add this value to it						
						var struct = target._schema;
						if (key=='_schema') {
							for (var key in target)
								ensureField(struct,key);
						} // else ignore the field
						else
							ensureField(struct,key);
					}
				}
				if (!target._notReady && oldValue !=NotReadyField && 
					oldValue !== value && notEqArrays(oldValue,value) && !(oldValue && oldValue._replaceWith == value)) {
					if (target._id && changeNotificationList[target._id])
						changeNotificationList[target._id](value);
//					if (!currentTransaction)		
	//					persevere.changedObject(target);
				}
			};
		pjs.monitor = function(object) {
			if (!object._id || object._id.substring(0,7) =="client/") throw new Error("You can not monitor a non-persisted object");
			monitoredObjects[object._id] = object;	
		}
		/**
		 * This function is creates a new object using the given basis object as the prototype. 
		 * This returns a new object with a basis of the provided basis parameter.
		 */
		pjs.newInstance = function(basis,args) {
			Construct = function(){};
			if (basis.hasOwnProperty('constructor')) 
				basis.constructor.prototype = basis; // just want to make sure it is correct
			else
				basis.constructor = Construct;
			Construct.prototype = basis;
			var obj = new Construct;
			if (args) {
				var frame = _frm(arguments);
				if (!frame.cp) {
					frame.obj = obj;
					frame.cp=1;
				}
				if (frame.obj.constructor.apply(frame.obj,args||[]) == Suspend) return frame.sus(this);
			}
			if (basis.constructor.prototype!=basis)
				debugger;
			return obj;
		}
		/**
		 * This function is creates a new object using the given schema object. 
		 * This returns a new object with it's schema defined by the schema object.
		 */
		pjs.newFromSchema = function(schema,args) {
			var newObj;
			if (typeof schema == 'function')
				newObj = new schema;
			else if (schema.prototype) {
				return pjs.newInstance(schema.prototype,[]); 
			}
			else
				newObj = {schema:schema};
			return newObj;
		}
		/**
		 * Returns an object with the given id
		 * @param id of the object to retrieve
		 * @return the object with given id
		 */
		pjs.load = function (id,callback,reload) {
			var val = dataTable[id];
			if (!val || val._notReady || reload) {
		 		if (requestData(id,null)== Suspend) return rerunLater(this,arguments);
			}
			val = dataTable[id];
	 		if ((val = ensureLoaded(val))== Suspend) return rerunLater(this,arguments);
			if (callback) callback(val);
			return val;
		};
		
		pjs.reload = function(id,callback) { return pjs.load(id,callback,true)}
		/**
		 * This enforces dynamic schema/property type checking
		 */
		var enforceFieldConstraints = function(obj, field, value) { 
			if (value === undefined)
				return;
			var schema = typeOf(obj);
			if (schema) {
				var fieldObject = get(schema,field);
			}
			if (!fieldObject)
				return; // TODO: This is only legal when the value that is being erased has a basis to inherit from, need to change this to check for that condition;
			else
				var requiredType = get(fieldObject,"type") || '*';
			if (obj[field] === undefined && field != "items") 
				var breakingSeal = get(schema,"sealed");
			if (breakingSeal) throw new Error("You can add an additional field to this object because it is sealed");
			var valueType = typeof value;
			var isObject = typeof requiredType == "object" && !(requiredType instanceof String);
			if (valueType != (isObject ? 'object' : requiredType) && requiredType != "*" && requiredType != "anything") // TODO: need to remove this
				throw new Error("You can not put a " + valueType + " in this field, a " + requiredType + " is required");
			if (isObject) {
				do {
					if (requiredType.isPrototypeOf(typeOf(value)))
						return;
				} while (value = getProto(value));
				throw new Error("This field requires an object of type " + requiredType.name || requiredType);
			}
		}
		var trans;
		var addToTransaction = function(id,object,method,rollback) {
			if (!currentTransaction) {
				currentTransaction = {rollbacks:[]};
				setTimeout(pjs.commit,1);
			}
			var objId = getId(object||1);
			trans = (objectsBeingPersised[objId]||0).object ? objectsBeingPersised[objId] : currentTransaction[objId] = currentTransaction[objId] || 
					{method:method, url : id,objId : objId, object: object, validAsOf:validAsOfTable[id] || new Date().getTime()};
			push(currentTransaction.rollbacks,rollback);
			trans.body = trans.object===undefined?"":JSON.stringify(exportable(trans.object,10,
							trans.url.substring(0, trans.url.lastIndexOf('/') + 1))); // calculate the source url
		}
			/**
			 * Retrieves a personal object for the current user that is persistable
			 */
			getUserData = pjs.getUserData = function (host){
				if (userData == Suspend) {
					userData = pjs.load((host || '')+ "userData");
				}
				return userData;
			}
			/**
			 * Returns the username of the current user. It returns undefined if there is no user logged in
			 */
			pjs.getUserName = function(host){
				return (readCookie((host||'') + 'Auth')||':').split(':')[0];
			}
			/** This function is called when ever a persistent field is accessed. Retrieves the 
			 * value of the given persistent field from the object. The Persistent JS syntax foo.bar should 
			 * return the same value as pjs.get(foo,"bar").
			 * */
			get = _g = pjs.get = function(obj,field,callback) {
				try {
					var retValue = obj[field];
				}
				catch (e) {
					throw new Error(obj + ' does not have a property ' + field);
				}
				if (!retValue) // the implicit conversion catches nulls as well, which returns a typeof = "object" so gets in the next block
				{
					if (obj._lengthLoaded && !isNaN(1*field) && field >= obj._lengthLoaded) {  
						var deepestBasis = obj;
						while (!deepestBasis.hasOwnProperty('_lengthLoaded'))
							deepestBasis = getProto(deepestBasis); // we must find the correct proto
						retValue = requestData(deepestBasis, field); // the basis value should contain this or whatever basis actually held the field that we are accessing
						if (retValue == Suspend) return rerunLater(this,arguments);
					}
					if (obj == Suspend) return rerunLater(this,arguments);
					if (this.access < 1) // Are we really going to this access level
						throw new Error("You do not have access to this object");				
				}
				else if (retValue._notReady) { 
					if (retValue.getter) {
					}
					else if (retValue._id)  {					
						if (dataTable[retValue._id]._notReady) 
							retValue = ensureLoaded(retValue);
						else
						{
							var deepestBasis = obj;
							while (!deepestBasis.hasOwnProperty(field))
								deepestBasis = getProto(deepestBasis); // we must find the correct proto						
							directSet(deepestBasis,field,retValue = dataTable[retValue._id]);
						}
					}
					else { // Can this be ensureLoaded
						if (retValue.perm === 0 || (retValue.perm === 1 && field != "name")) { 
							return accessDenied(retValue);
						}
						var deepestBasis = obj;
						while (!deepestBasis.hasOwnProperty(field))
							deepestBasis = getProto(deepestBasis); // we must find the correct proto
						retValue = requestData(deepestBasis, field); // the basis value should contain this or whatever basis actually held the field that we are accessing
						if (retValue != _S)
							retValue = get(obj,field);
					}
					if (retValue.getter) {
						if (!callback || typeof callback == 'function') 
							retValue = retValue.getter.call(obj);							
					}
					if (retValue == Suspend) return rerunLater(this,arguments);
				}
				if (typeof callback == 'function')
					callback(retValue);
				return retValue;
			}
			_p = function(obj,field,value) { 
				if (obj._id && isPersisted(obj)) {
					var schema;						
					if ((schema = typeOf(obj)) ==Suspend) return rerunLater(this,arguments);
					if (!schema[field])
						return obj[field] = value;
					return pjs.set(obj,field,value);
				}
				else
					return obj[field] = value;					
			}
			/**
			 * This sets the given value into the given persistent field from the object. 
			 * This returns the value that was set.
			 * @param object The object to set the persistent field on
			 * @param field The field to set
			 * @param value The value to set in the field (if no value is provided, then the field will be removed)
			 * @param noSetter optional value to indicate to ignore setters
			 * @return the value that was set
			 */
			pjs.set = function(obj,field,value,noSetter) {
				if (typeof field == "number" && obj.splice) 
					return obj.splice(field,1,value);
				if (obj._schema) {
					var schema;
					schema=typeOf(obj);
					var trans = get(schema,field) && get(schema,field)['transient'];
				}
				if (obj._id && obj.hasOwnProperty('_id') && !trans && isPersisted(obj) && obj._id.charAt(0)!='s') {
					//if (obj[field] === value && obj.hasOwnProperty(field))  // if it is already set we don't need to do anything we can return
						//return value; 
					var accessLevel = pjs.getAccessLevel(obj);
					if (accessLevel < 5) 
						return accessDenied(obj,true);
					
					enforceFieldConstraints(obj,field,value); 
					var oldValue = get(obj,field,true);
					if (oldValue && oldValue.setter)
						return oldValue.setter.call(obj,value);
					directSet(obj,field,value);
					addToTransaction(obj._id,obj,2,function() { directSet(obj,field,oldValue);});
					/* This code does the set, and we may not want it to run until after the transaction has committed */
				}
				else {// we have the only copy of this object locally
					obj[field] = value;
				}

				return value;
			}

			/**
			 * Returns the access level of the current user on the given object. The access level should
			 * be an integer denoted a permission according to this table:
			 * 0 - none - can not access any of the fields on this object
			 * 1 - browse - can only read from a limited set of fields (usually name and basis)
			 * 2 - read - can read all the information from this object, but can not make any modifications to this object
			 * 3 - append - for list objects, entries can be appended, but no property modifications can be made
			 * 5 - write - any modifications can be made to this object
			 * Note that Persistent JavaScript is garbage collection based so there is no concept of deleting an object, only properties. Objects are deleted when all references to them are removed
			 */
		pjs.getAccessLevel = function(obj) {
				return obj.hasOwnProperty('_id') ? accessLevel[obj._id] || (obj._id.charAt(0)=='s' ? 2 : 5) : 5;
			}
		pjs.createNewInList = function(list) { 
				var fields =get(list,"_schema");
				if (fields) {
					var basis = get(get(fields,"items"),"type");
					if (basis == Suspend) return rerunLater(this,arguments);
					return list.push(pjs.newInstance(basis));
				}
				else
					return list.push({});
			}
		function convertMethodToFunction(func) {
			return function() {
				var newArgs = [];
				for (var i = 1; i < arguments.length; i++)
					push(newArgs,arguments[i]);		
				return func.apply(arguments[0],newArgs);
			}
		}

		/**
		 * Alter the Array prototype functions
		 */
		var superSplice = arrayProto.splice;
			/**
			 * Array.indexOf( value, begin, strict ) - Return index of the first element that matches value
			 */ 
		var indexOf = function( v, b) {
			 for( var i = +b || 0, l = this.length; i < l; i++ ) {
			  if(this[i]==v) { return i; }
			 }
			 return -1;
		}
		if (arrayProto.indexOf) 
			arrayProto.indexOf = indexOf;
		Array.indexOf = indexOf = convertMethodToFunction(indexOf);
			/**
			 * Iterate through the persistent array object
			 */
		var iterFunc = function(mode) {
			return function(func,scope) {
			var obj;
			if (!(this instanceof Array))
				throw new Error("Incompatible object, array is required");
			var frame = _frm(arguments);
			if (!frame.scp) func = frame[0];
			_s:while(1){switch(frame.cp){case undefined:
			frame.i=-1;
			case 1:
			frame.i++;frame.cp=3;case 3:
//			if (frame.i==length) return;
			if((obj=get(this,frame.i))==Suspend){break _s}
			if(obj===undefined && frame.i>=this.length){return;} // not sure how else to test for the end of the array
			if((obj=func.call(scope,obj,frame.i,this))==Suspend){break _s}frame.cp=((mode==1&&obj) || (mode==-1&&!obj))?2:1;break;case 2:return}}
			return frame.sus(func,frame.cp,this);
			}
		}	
		if (arrayProto.forEach)
			arrayProto.forEach = iterFunc();
		Array.forEach = forEach = convertMethodToFunction(iterFunc());
		if (arrayProto.some)
			arrayProto.some = iterFunc(1);
		Array.some = convertMethodToFunction(iterFunc(1));
		if (arrayProto.every)
			arrayProto.every= iterFunc(-1);
		Array.every = convertMethodToFunction(iterFunc(-1));
		Array.remove = function(array,value) {
			// TODO: Need to send a remove command to the server by id instead of by index
			if (isPersisted(array)) 
				addToTransaction(array._id + '[?(' + (value._id ? '@.id="' + value._id + '"' : JSON.stringify(value)) + ')]',value,
					3,function() {
						superSplice.call(array,i,0,value);
					});
			for (var i = 0; i < array.length; i++) // only need to remove from the loaded items
				if (array[i] === value) {
					return superSplice.call(array,i,1);
				}			 
		}
			Array.getLength = function(array) { // TODO: Get rid of this
				if (getProto(array) && isIE) {
					var length = -1;
					if (Array.forEach(array,function(obj,i) {length=i}) == Suspend) return rerunLater(this,arguments);
					return length+1;
				}
				return array.length;
			}
			/**
			 * Push an object on the array object
			 */
			arrayProto.push = function(value,initialize) {
				if (!this._id) 
					return push(this,value);
				
				var frame = _frm(arguments);
				var accessLevel = pjs.getAccessLevel(this);
				if (accessLevel == Suspend) return rerunLater(this,arguments);
				if (accessLevel < 4) 
					accessDenied(this,true);
				if (enforceFieldConstraints(this,"items",value) == Suspend) return rerunLater(this);
				push(this,value);
				if (!initialize) {
					var _this = this;
					addToTransaction(this._id,value,1,function() {
						superSplice.call(_this,_this.length-1,1);
					});
				}
				if (changeNotificationList[this._id])
					changeNotificationList[this._id](value);
				return value;
			}
			/**
			 * Splice on the persistent array object. Works like the JavaScript array function
			 */
			arrayProto.splice = function(index,howMany) { 				
				if (!this._id)	 // TODO: need to perform special action for IE
					return superSplice.apply(this,arguments);
				var frame = _frm(arguments);
				if (frame.scp) {
					frame.index = index;
					frame.howMany = howMany;
				} 
				var accessLevel = pjs.getAccessLevel(this);
				if (accessLevel < 5) 
					accessDenied(this,true);
				var values = [];
				for (var i = 2; i < frame.args.length; i++)  {// these are the indices of objects that will be added to the array
					if (frame.args[i] !== undefined) {
						if (enforceFieldConstraints(this,"items",frame.args[i]) == Suspend) return rerunLater(this,arguments);
						push(values,frame.args[i]);
					}
				}
				watching=0;
				var retValue = superSplice.apply(this,frame.args);
				// it is possible for retValue to need to be cause a suspend, but we can't accept a callback handler, because the parameters are not defined in a length, they end with a list of values to add
				watching=1;
				var _this = this;
				addToTransaction(this._id,this,2,function() {
					superSplice.apply(_this,[index,frame.args.length-2].concat(retValue));
				});
				if (changeNotificationList[this._id])
					changeNotificationList[this._id]();
				return retValue;
		}
		arrayProto.pop = function(str) {
			var lastIndex = Array.getLength(this) -1;
			var last = this[lastIndex];
			this.splice(lastIndex,1);
			return last;
		}
		function fixRewriters(method) {
			var old = arrayProto[method];
			arrayProto[method] = function() {
				this.splice.apply(this,[0,Array.getLength(this)].concat(old.call(this.concat([])))); // create a copy and perform the action and replace everything with splice
				return this;
			}
		}
		fixRewriters('reverse');
		fixRewriters('sort');
		arrayProto.shift= function() {
			var first = this[0];
			this.splice(0,1);
			return first;
		}
		arrayProto.unshift= function(val) {
			this.splice(0,0,val);
		}
		var POSSIBLE_METHODS = ['join','toSource','sort','pop','reverse','concat','every','filter','lastIndexOf','map','slice','some','reduce','reduceRight','shift'];
		for (var i = 0; i < POSSIBLE_METHODS.length; i++) {
			(function(method,callbackFirstArg) {
				var old = arrayProto[method];
				function loadArray() {
					for (var i in this)
						if (this[i] && this[i]._notReady && get(this,i) == Suspend) 
							return rerunLater(this,arguments);
					var last = arguments.length -1;
					var callback = arguments[last]; 					
					if (typeof callback == 'function' && (callbackFirstArg || last)) 
						arguments.length = last;
					var retValue = old.apply(this,arguments);
					if (typeof callback == 'function' && (callbackFirstArg || last)) 
						callback(retValue);
					return retValue;
				}
				if (old) 
					arrayProto[method] = loadArray;
			})(POSSIBLE_METHODS[i],i<6); // the first six can have the callback as the first arg, the rest can not
		}		
		/** 
		* Constructor of a new persistent method object. If you want to save a function on a persistent object you should use this instead of normal function
		* construction.
		* */
	pjs.Function =function(source,methodThis,runAt) { // TODO: This should go away and we should be able to set a function by just inserting a normal function
			if (pjs.load("js/compiler.js") == Suspend) return rerunLater(this,arguments);
			return strands.compiler.Function(source,methodThis,runAt);
		}
	pjs.GetterSetter = function() {
		var func;
		if ((func = pjs.Function("function() { return null;}"))==Suspend) return rerunLater(this,arguments);
			this.getter =func;
		if ((func = pjs.Function())==Suspend) return rerunLater(this,arguments);
			this.setter =func;
		this._notReady = 1;
	}
	
	/**
	 * This is called when an object is changed. 
	 */	
	persevere.changedObject = function(changedObject) {};
	/**
	 * This will check the monitored list of objects for changes from the server
	 */
	pjs.checkForChanges= function() {
		var objects="[";
		var validAsOf = 9999999999999;
		for (var i in monitoredObjects) {
			objects += "'" + i + "',";
			if (validAsOfTable[monitoredObjects[i]._id] < validAsOf)
				validAsOf = validAsOfTable[monitoredObjects[i]._id];
		}
		if (objects.length > 1) 
			request(0,{Get:objects + "]",changesSince:validAsOf},0); // TODO: Make it have no status message
	}
})();

var watching;
function watcher(key,old,value) {// this has to be top level or it will leak memory in firefox, TODO: Switch to __defineSetter__ to improve performance 
	return watching?pjs.set(this,key,value):value;
}
 
function assert(test,message) {
	if (!test)
		throw new Error(message || "Assertion failure");
}
